//////////////////////////////////////////////////////////////////////////////
//
//  Created by Philip Mulcahy on 15/01/2013.
//  Copyright (c) 2013 Philip Mulcahy. All rights reserved.
//
//  This file is part of the note-recog library.
//
//  note-recog is free software: you can redistribute it and/or modify
//  it under the terms of version 3 of the GNU Lesser General Public License 
//  as published by the Free Software Foundation.
//
//  note-recog is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with note-recog. If not, see <http://www.gnu.org/licenses/>.
//
//////////////////////////////////////////////////////////////////////////////

#ifndef note_recog_TestRun_h
#define note_recog_TestRun_h

#include "IIterable.h"
#include "Log.h"
#include "FastFourierTransform.h"
#include "SequenceIO.h"
#include "ITestSpec.h"
#include "SequenceIO.h"
#include <sstream>
#include <vector>

template<typename EventType>
class TestRun
{
private:
    ITestSpec<EventType>& _spec;
    LOG_DECLARE;
public:
    TestRun(ITestSpec<EventType>&);
    virtual bool execute();
};

template<typename EventType>
LOG_DEFINE(TestRun<EventType>);

template<typename EventType>
TestRun<EventType>::TestRun(ITestSpec<EventType>& spec)
: _spec(spec)
{}


template<typename EventType>
bool TestRun<EventType>::execute()
{
    std::vector<short> time_domain;
    EventCollection<EventType> achieved;
    const EventCollection<EventType> expected = _spec.expectedEvents();
    std::unique_ptr<Detector> subject(_spec.createSubject(achieved));
    std::unique_ptr<IIterable<Frame>> frames = _spec.createFrames();
    while(frames->hasNext())
    {
        Frame f = frames->next();
        const std::vector<short> segment = f.time_domain();
        time_domain.insert(time_domain.end(), segment.begin(), segment.end());
        subject->submitFrame(f);
    }
    
    std::set<typename EventCollection<EventType>::Difference> differences
      = expected.compare(achieved);
  
    size_t diff_tolerance = expected.size()/13; // As strict as I could get away with
    if(differences.size() <= diff_tolerance)
    {
        return true;
    }
    
    LOG_INFO("expected size " << expected.size());
    LOG_INFO("achieved size " << achieved.size());
    LOG_INFO("differences size " << differences.size());
    LOG_INFO("expected: " << expected);
    LOG_INFO("achieved: " << achieved);
    LOG_INFO("differences: " << differences);
    
    const std::vector<float> expected_timestamps = expected.timeStamps();
    const std::vector<float> achieved_timestamps = achieved.timeStamps();
    
    SequenceIO::write(time_domain.begin(), time_domain.end(),
                      "/Users/philip/tmp/time_domain.txt");
    SequenceIO::write(expected_timestamps.begin(), expected_timestamps.end(),
                      "/Users/philip/tmp/expected_timestamps");
    SequenceIO::write(achieved_timestamps.begin(), achieved_timestamps.end(),
                      "/Users/philip/tmp/achieved_timestamps");
    return false;
}


#endif
